package org.xliu.cs.openproject.codegenerator;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.xliu.cs.openproject.codegenerator.pojo.JavaClass;
import org.xliu.cs.openproject.codegenerator.pojo.JavaElement;
import org.xliu.cs.openproject.codegenerator.pojo.JavaEnum;
import org.xliu.cs.openproject.codegenerator.pojo.PackageScanner;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

// POJO转换器
public class JavaToCppPojoConverter {
    private static final Template template;
    private static final Template enumTemplate;

    // 初始化Velocity
    static {
        Properties props = new Properties();
        props.setProperty("resource.loader", "class");
        props.setProperty("class.resource.loader.class",
                "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(props);
        // 获取模板
        template = Velocity.getTemplate("templates/template.h");
        enumTemplate = Velocity.getTemplate("templates/enum_template.h");
    }

    // 生成C++类代码
    private static void generateCppClass(JavaClass javaClass, Path outFilePath) {
        try {
            // 创建上下文并添加数据模型
            VelocityContext context = new VelocityContext();
            context.put("javaClass", javaClass);

            // 处理模板并生成输出
            try (BufferedWriter writer = Files.newBufferedWriter(outFilePath)) {
                template.merge(context, writer);
            }
        } catch (ResourceNotFoundException e) {
            System.err.println("模板文件未找到: " + e.getMessage());
        } catch (ParseErrorException | MethodInvocationException e) {
            System.err.println("模板处理错误: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("生成C++代码时出错: " + e.getMessage());
        }
    }

    // 生成C++枚举代码
    private static void generateCppEnum(JavaEnum javaEnum, Path outFilePath) {
        try {
            // 创建上下文并添加数据模型
            VelocityContext context = new VelocityContext();
            context.put("javaEnum", javaEnum);

            // 处理模板并生成输出
            try (BufferedWriter writer = Files.newBufferedWriter(outFilePath)) {
                enumTemplate.merge(context, writer);
            }
        } catch (ResourceNotFoundException e) {
            System.err.println("枚举模板文件未找到: " + e.getMessage());
        } catch (ParseErrorException | MethodInvocationException e) {
            System.err.println("枚举模板处理错误: " + e.getMessage());
        } catch (Exception e) {
            System.err.println("生成C++枚举代码时出错: " + e.getMessage());
        }
    }

    public static void generate(String packageName, String outPath) throws IOException {
        // 通过包扫描获取JavaClass和JavaEnum
        List<JavaClass> javaClasses = new ArrayList<>();
        List<JavaEnum> javaEnums = new ArrayList<>();

        // 统一扫描包中的所有类（包括普通类和枚举）
        List<JavaElement> scannedClasses = PackageScanner.scanPackage(packageName);

        Path path = Paths.get(outPath);
        Files.createDirectories(path);

        // 分离普通类和枚举类
        for (JavaElement element : scannedClasses) {
            if (element instanceof JavaClass) {
                javaClasses.add((JavaClass) element);
            } else if (element instanceof JavaEnum) {
                javaEnums.add((JavaEnum) element);
            }
        }

        // 处理扫描到的类
        if (javaClasses.isEmpty() && javaEnums.isEmpty()) {
            System.out.println("未找到任何类或枚举，请检查包路径是否正确。");
            return;
        }


        // 生成类的C++代码
        for (JavaClass javaClass : javaClasses) {
            generateCppClass(javaClass, Paths.get(path.toString(), javaClass.getClassName() + ".h"));
        }

        // 生成枚举的C++代码
        for (JavaEnum javaEnum : javaEnums) {
            generateCppEnum(javaEnum, Paths.get(path.toString(), javaEnum.getEnumName() + ".h"));
        }
    }
}